from Services.Service import ServicePool
from singleton import singleton
from Containers.Container import Containerize, AnonymusContainer

import json, time

@singleton
class Registry:
    system_table = "__RegistrySettings"

    def __init__(self):
        self.load()
        if self.registry == {}:
            self.Call(None, ("create_table", "__RegistrySettings"))
            self.Call(None, ("set", "__RegistrySettings", "table", "__RegistrySettings"))
            self.Call(None, ("set", "__RegistrySettings", "file", "/registry.rdb"))
            self.Call(None, ("set", "__RegistrySettings", "compression", False))

    registry = {}

    def Call(self, pipe_id, data):
        operations = {
            "get": self.get_record,
            "create_table": self.create_table,
            "set": self.set_record,
            "delete_table": self.delete_table,
            "delete_record": self.delete_record,
            "get_all_records": self.get_all_records,
            "get_tables": self.get_tables,
            "select": self.select_records,
            "save": self.save,
            "load": self.load,
            "execute": self.execute_command,
            "insert": self.insert
        }
        if not isinstance(data, tuple):
            return False, "data must be a tuple"

        operation, *args = data
        if operation not in operations:
            return False, f"Unknown operation: {operation}"

        try:
            operation_func = operations[operation]
            result = operation_func(pipe_id, *args)
            return True, result
        except Exception as e:
            return False, str(e)

    #@Containerize(AnonymusContainer)
    def save(self):
        name = self.get_record(None, 
            table_name=self.system_table,
            key="file"
        )
        with open(name if name else "/registry.rdb", 'w') as file:
            #file.write(zlib.compress(json.dumps(self.registry).encode()))
            json.dump(self.registry, file)

    def load(self):
        try:
            name = self.get_record(None, table_name=self.system_table, key="file")

            with open(name if name else "/registry.rdb") as file:
                self.registry = json.load(file)
        except Exception as e:
            print(e)
            self.registry = {}

    def get_record(self, pipe_id, table_name, key):
        table = self.registry.get(table_name, {})
        return table.get(key, False)

    def create_table(self, pipe_id, table_name):
        self.registry[table_name] = {}
        self.save()
        return True

    def set_record(self, pipe_id, table_name, key, value):
        table = self.registry.get(table_name, {})
        table[key] = value
        self.registry[table_name] = table
        self.save()
        return True

    def get_tables(self, _=None):
        return list(self.registry.keys())

    def delete_table(self, pipe_id, table_name):
        if table_name in self.registry:
            del self.registry[table_name]
            self.save()
            return True
        self.save()
        return False

    def delete_record(self, pipe_id, table_name, key):
        table = self.registry.get(table_name, {})
        if key in table:
            del table[key]
            self.registry[table_name] = table
            self.save()
            return True
        self.save()
        return False

    def get_all_records(self, pipe_id, table_name):
        table = self.registry.get(table_name, {})
        return table.copy()

    def select_records(self, pipe_id, table_name, condition):
        table = self.registry.get(table_name, {})
        selected_records = {}
        for key, value in table.items():
            if condition(value):
                selected_records[key] = value
        return selected_records

    def insert(self, pipe_id, table_name, records_dict):
        table = self.registry.get(table_name, {})
        for key, value in records_dict.items():
            table[key] = value
        self.registry[table_name] = table
        self.save()
        return True

    def execute_command(self, pipe_id, command_str):
        start_time = time.ticks_ms()
        args = command_str.split()
        operation = args[0]
        params = args[1:]

        if operation == "get":
            table_name, key = params
            success, result = self.Call(None, (operation, table_name, key))

        elif operation == "create_table":
            table_name = params[0]
            success, result = self.Call(None, (operation, table_name))

        elif operation == "set":
            params = command_str.split(' ', 3)
            table_name, key, value = params[1:4]
            #print(table_name, key, value)
            success, result = self.Call(None, (operation, table_name, key, eval(value)))

        elif operation == "delete_record":
            table_name, key = params
            success, result = self.Call(None, (operation, table_name, key))

        elif operation == "delete_table":
            table_name = params[0]
            success, result = self.Call(None, (operation, table_name))

        elif operation == "select":
            table_name = params[0]
            condition = ' '.join(params[1:])
            if condition in ['*', 'any', 'all']:
                condition = 'True'
            condition = eval(f"lambda record: {condition}")
            success, result = self.Call(None, (operation, table_name, condition))

        elif operation == "get_tables":
            success, result = self.Call(None, (operation,))

        else:
            success = False
            result = f"Unknown operation: {operation}"

        execution_time = time.ticks_ms() - start_time
        return success, result, execution_time

ServicePool().CreateService("Registry", Registry().Call) # Регистрируем новый сервис
ServicePool().CreateService("RegistryInstance", lambda _, d: Registry())
#TODO: сделать проверку работы

'''
Пример работы:

ServicePool().CallService("Registry", ("create_table", "test"))
ServicePool().CallService("Registry", ("set", "test", "key", "Hello"))
result = ServicePool().CallService("Registry", ("get", "test", "key"))
print(result)

или так:
import random
import string

table_name = "test_table"
random_key = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
random_value = ''.join(random.choices(string.ascii_letters + string.digits, k=16))

# Создаем таблицу
success, result = ServicePool().CallService("Registry", ("create_table", table_name))
if not success:
    print(f"Ошибка создания таблицы '{table_name}': {result}")
    return

# Проверяем наличие таблицы
tables = ServicePool().CallService("Registry", ("get_tables",))
if table_name not in tables[1]:
    print(f"Таблица '{table_name}' не найдена в списке таблиц")
    return

# Записываем случайное значение в таблицу
success, result = ServicePool().CallService("Registry", ("set", table_name, random_key, random_value))
if not success:
    print(f"Ошибка записи в таблицу '{table_name}': {result}")
    return

# Проверяем корректность записи
success, retrieved_value = ServicePool().CallService("Registry", ("get", table_name, random_key))
if not success or retrieved_value != random_value:
    print(f"Ошибка проверки записи в таблице '{table_name}'. Ожидалось: {random_value}, получено: {retrieved_value}")
    return

print("Реестр исправен и работает корректно")
'''
